﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Algobox.JuicyLib.MarketData;
using Algobox.JuicyLib.SQL.LiquidView;

namespace Algobox.JuicyLib.Apps.RealTickImporter
{
    public class RealTickImporter
    {
        public RealTickImporter(string connectionStringIn)
        {
            connectionString = connectionStringIn;

            if (connectionString != string.Empty)
            {
                sqlImporter = new Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext(connectionStringIn);
            }
            else
            {
                sqlImporter = new Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext();
            }
        }

        /// <summary>
        /// dsn connection string 
        /// </summary>
        public string ConnectionString
        {
            get { return connectionString; }
            set { connectionString = value; }
        }
        private string connectionString = null;


        /// <summary>
        /// Search string for files to import
        /// </summary>
        private const string PREFIXEXECUTIONS = "_EXECUTIONS_";
        
        /// <summary>
        /// Field delimiter of file
        /// </summary>
        private const char DELIMITER = ',';

        private const string HOSTNAME = "RealTickFtpImport";
        private const string HOSTTYPE = "RealTick";

        /// <summary>
        /// MS generated sql class to access trade/order input sps
        /// </summary>
        Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext sqlImporter = null;

        private Mode mode = Mode.Executions;

        /// <summary>
        /// File types
        /// </summary>
        private enum Mode
        {
            Executions,
            GroupedExecutions
        }

        private enum SecurityTypes
        {
            Stock = 1,
            StockOption = 2,
            Future = 3,
            FutureOption = 4,
            Spot = 5,
            Warrant = 6,
            CorporateBond = 7,
            MutualFund = 8,
            GovtBond = 9,
            FuturesIndex = 10,
            SingleStockFuture = 17,
            Forex = 18
        }
        
        private enum LiqAssetTypes
        {
            Stock = 'S',
            Cash = 'C',
            Future = 'F',
            FX = 'X',
            Option = 'O'
        }

        private enum FileFields
        {
            OriginalOrderID, // = 0
            OrderId,
            OriginalTradeDate,
            TradeDate,
            OriginalTradeTime,
            TradeTime,
            SettlementDate,
            OriginalOrderVolume,
            Volume,
            ResidualVolume,
            SecurityType,
            Symbol,
            Exchange,
            Cusip,
            ISIN,
            StrikePrice,
            Expiration,
            PutCallIndicator,
            Side,
            OpenClose,
            Price,
            StopPrice,
            GoodUntil,
            Commission,
            User,
            Domain,
            Bank,
            Branch,
            Customer,
            Deposit,
            Contra,
            Broker,
            OppositeParty,
            OrderTag,
            TicketId,
            OatsId,
            NotHeld,
            Currency,
            SellingMethod // = 38
        }


        /// <summary>
        /// use filename to determine if we should process
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public bool FilterFileName(string fileName)
        {
            if (fileName.IndexOf(PREFIXEXECUTIONS) > 0)
            {
                mode = Mode.Executions;
                return true;
            }
            else
            {
                return false;
            }
        }


        public void Log(string message)
        {
            sqlImporter.ExceptionHandlerThrow("RealTickImporter", message, null);
        }

        /// <summary>
        /// process the file
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public bool ProcessStream(StreamReader reader)
        {
            string fileLine;
            string[] arrayData;
            int securityType = 0;
            bool ret;

            try
            {
                while (reader.BaseStream.CanRead && !reader.EndOfStream)
                {
                    fileLine = reader.ReadLine();

                    arrayData = fileLine.Split(DELIMITER);


                    // check that this line contains some data
                    if (arrayData.Length > (int)FileFields.SecurityType)
                    {
                        if (int.TryParse(arrayData[(int)FileFields.SecurityType], out securityType))
                        {
                            securityType = 0;
                            ret = false;

                            System.Console.WriteLine(fileLine);

                            switch ((SecurityTypes)securityType)
                            {
                                case SecurityTypes.Stock:
                                    ret = ProcessStockTrade(arrayData);
                                    if (!ret)
                                        Log("ProcessStockTrade Failed: " + fileLine);
                                    break;
                                case SecurityTypes.Future:
                                    ret = ProcessFutureTrade(arrayData);
                                    if (!ret)
                                        Log("ProcessFutureTrade Failed: " + fileLine);
                                    break;
                                default:
                                    Log("New security type unhandled: " + ((SecurityTypes)securityType).ToString());
                                    Log("Unhandled line: " + fileLine);
                                    break;
                            }
                        }
                    }

                }
            }
            catch (Exception e)
            {
                Log("Caught Exception in RealTickImporter.ProcessStream(), message was: " + e.Message);
            }

            return true;
        }

        int count = 0;
        /// <summary>
        /// Process stock trade
        /// </summary>
        /// <param name="data"></param>
        private bool ProcessStockTrade(string[] data)
        {
            string currency = string.Empty;
            decimal price = 0;

            try
            {
                bool isGBXorGBp = false;

                currency = MarketDataHelper.ConvertGBXGBpToGBP(data[(int)FileFields.Currency], out isGBXorGBp);
                if (isGBXorGBp)
                    price = decimal.Parse(data[(int)FileFields.Price]) / 100;
                else
                    price = decimal.Parse(data[(int)FileFields.Price]);

                // this isn't always the sedol, but it is most of the time, so better than sending nothing!
                string sedol = data[(int)FileFields.ISIN].Substring(4,7);

                string side = data[(int)FileFields.Side].Substring(0, 1);

                sqlImporter.ImportTrade(
                    (char)LiqAssetTypes.Stock,
                    HOSTNAME,
                    HOSTTYPE,
                    data[(int)FileFields.OriginalOrderID],
                    data[(int)FileFields.OrderId],
                    data[(int)FileFields.Exchange],
                    data[(int)FileFields.OriginalOrderID],
                    data[(int)FileFields.OrderId],
                    data[(int)FileFields.Deposit],
                    currency,
                    data[(int)FileFields.ISIN],
                    sedol,
                    null,
                    data[(int)FileFields.Symbol],
                    null,
                    null,
                    null,
                    side == "S" ? -(long.Parse(data[(int)FileFields.Volume])) : long.Parse(data[(int)FileFields.Volume]),
                    price,
                    //DateTime.Parse(data[(int)FileFields.TradeDate] + " " + data[(int)FileFields.TradeTime]),
                    DateTime.ParseExact(data[(int)FileFields.TradeDate] + " " + data[(int)FileFields.TradeTime], "yyyyMMdd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture),
                    HOSTTYPE,
                    null,
                    false,
                    false,
                    false,
                    null,
                    data[(int)FileFields.Contra],
                    null,
                    null,
                    null);
            }
            catch (Exception e)
            {
                Log("ProcessStockTrade Failed: " + e.ToString());
                return false;
            }

            return true;
        }


        /// <summary>
        /// Process stock trade
        /// </summary>
        /// <param name="data"></param>
        private bool ProcessFutureTrade(string[] data)
        {
            try
            { 
                // this isn't always the sedol, but it is most of the time, so better than sending nothing!
                string sedol = data[(int)FileFields.ISIN].Substring(4, 7);

                string side = data[(int)FileFields.Side].Substring(0, 1);

                sqlImporter.ImportTrade(
                    (char)LiqAssetTypes.Future,
                    HOSTNAME,
                    HOSTTYPE,
                    data[(int)FileFields.OriginalOrderID],
                    data[(int)FileFields.OrderId],
                    data[(int)FileFields.Exchange],
                    data[(int)FileFields.OriginalOrderID],
                    data[(int)FileFields.OrderId],
                    data[(int)FileFields.Deposit],
                    data[(int)FileFields.Currency],
                    data[(int)FileFields.ISIN],
                    null,
                    null,
                    data[(int)FileFields.Symbol],
                    DateTime.ParseExact(data[(int)FileFields.Expiration], "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture),
                    null,
                    null,
                    side == "S" ? -(long.Parse(data[(int)FileFields.Volume])) : long.Parse(data[(int)FileFields.Volume]),
                    decimal.Parse(data[(int)FileFields.Price]),
                    //DateTime.Parse(data[(int)FileFields.TradeDate] + " " + data[(int)FileFields.TradeTime]),
                    DateTime.ParseExact(data[(int)FileFields.TradeDate] + " " + data[(int)FileFields.TradeTime], "yyyyMMdd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture),
                    HOSTTYPE,
                    null,
                    false,
                    false,
                    false,
                    null,
                    data[(int)FileFields.Contra],
                    null,
                    null,
                    null);
            }
            catch (Exception e)
            {
                Log("ProcessFutureTrade Failed: " + e.ToString());
                return false;
            }

            return true;
        }

    }
}
